﻿using System.Diagnostics;
using System.Collections.Generic;
using System.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;
using Microsoft.Practices.EnterpriseLibrary.Logging.Instrumentation;
using Microsoft.Practices.ServiceLocation;

namespace Dynamic.Facades.EntLib.Logging
{
    /// <summary>
    /// 日志类，包括了日志的基本操作
    /// </summary>
    public static class Logger
    {
        private static object sync = new object();
        private static volatile LogWriter writer;

        private const EventCategory DefaultCategory = EventCategory.General;
        private const int DefaultPriority = -1;
        private const TraceEventType DefaultSeverity = TraceEventType.Information;
        private const int DefaultEventId = 1;
        private const string DefaultTitle = "";

        /// <summary>
        /// 设置上下文环境
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void SetContextItem(object key, object value)
        {
            Writer.SetContextItem(key, value);
        }

        /// <summary>
        /// 清空上下文环境
        /// </summary>
        public static void FlushContextItems()
        {
            Writer.FlushContextItems();
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        public static void Write(object message)
        {
            Write(message, DefaultCategory, DefaultPriority,
                  DefaultEventId, DefaultSeverity, DefaultTitle, null);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        public static void Write(object message, EventCategory category)
        {
            Write(message, category, DefaultPriority, DefaultEventId, DefaultSeverity, DefaultTitle, null);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="priority"></param>
        public static void Write(object message, EventCategory category, int priority)
        {
            Write(message, category, priority, DefaultEventId, DefaultSeverity, DefaultTitle, null);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="priority"></param>
        /// <param name="eventId"></param>
        public static void Write(object message, EventCategory category, int priority, int eventId)
        {
            Write(message, category, priority, eventId, DefaultSeverity, DefaultTitle, null);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="priority"></param>
        /// <param name="eventId"></param>
        /// <param name="severity"></param>
        public static void Write(object message, EventCategory category, int priority, int eventId, TraceEventType severity)
        {
            Write(message, category, priority, eventId, severity, DefaultTitle, null);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="priority"></param>
        /// <param name="eventId"></param>
        /// <param name="severity"></param>
        /// <param name="title"></param>
        public static void Write(object message, EventCategory category, int priority, int eventId,
                                 TraceEventType severity, string title)
        {
            Write(message, category, priority, eventId, severity, title, null);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="properties"></param>
        public static void Write(object message, IDictionary<string, object> properties)
        {
            Write(message, DefaultCategory, DefaultPriority,
                  DefaultEventId, DefaultSeverity, DefaultTitle, properties);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="properties"></param>
        public static void Write(object message, EventCategory category, IDictionary<string, object> properties)
        {
            Write(message, category, DefaultPriority, DefaultEventId, DefaultSeverity,
                  DefaultTitle, properties);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="priority"></param>
        /// <param name="properties"></param>
        public static void Write(object message, EventCategory category, int priority, IDictionary<string, object> properties)
        {
            Write(message, category, priority, DefaultEventId, DefaultSeverity, DefaultTitle, properties);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="category"></param>
        /// <param name="priority"></param>
        /// <param name="eventId"></param>
        /// <param name="severity"></param>
        /// <param name="title"></param>
        /// <param name="properties"></param>
        public static void Write(object message, EventCategory category, int priority, int eventId,
                                 TraceEventType severity, string title, IDictionary<string, object> properties)
        {
            ICollection<string> categories = category.ToString().Split(',');

            Write(message, categories, priority, eventId, severity, title, properties);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="categories"></param>
        /// <param name="priority"></param>
        /// <param name="eventId"></param>
        /// <param name="severity"></param>
        /// <param name="title"></param>
        /// <param name="properties"></param>
        public static void Write(object message, ICollection<string> categories, int priority, int eventId,
                                 TraceEventType severity, string title, IDictionary<string, object> properties)
        {
            LogEntry log = new LogEntry();
            log.Message = message.ToString();
            log.Categories = categories;
            log.Priority = priority;
            log.EventId = eventId;
            log.Severity = severity;
            log.Title = title;
            log.ExtendedProperties = properties;

            Write(log);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="log"></param>
        public static void Write(LogEntry log)
        {
            Writer.Write(log);
        }

        /// <summary>
        /// 得到过虑
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetFilter<T>()
            where T : class, ILogFilter
        {
            return Writer.GetFilter<T>();
        }

        /// <summary>
        /// 得到过虑
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        public static T GetFilter<T>(string name)
            where T : class, ILogFilter
        {
            return Writer.GetFilter<T>(name);
        }

        /// <summary>
        /// 得到过虑
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static ILogFilter GetFilter(string name)
        {
            return Writer.GetFilter(name);
        }

        /// <summary>
        /// 判断日志是否可用
        /// </summary>
        /// <returns></returns>
        public static bool IsLoggingEnabled()
        {
            return Writer.IsLoggingEnabled();
        }

        /// <summary>
        /// 日志实体已经被写
        /// </summary>
        /// <param name="log"></param>
        /// <returns></returns>
        public static bool ShouldLog(LogEntry log)
        {
            return Writer.ShouldLog(log);
        }

        /// <summary>
        /// 重置
        /// </summary>
        public static void Reset()
        {
            lock (sync)
            {
                LogWriter oldWriter = writer;

                writer = null;

                if (oldWriter != null)
                    oldWriter.Dispose();
            }
        }

        /// <summary>
        /// 日志写属性
        /// </summary>
        public static LogWriter Writer
        {
            get
            {
                if (writer == null)
                {
                    lock (sync)
                    {
                        if (writer == null)
                        {
                            try
                            {
                                writer = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
                            }
                            catch (ActivationException configurationException)
                            {
                                TryLogConfigurationFailure(configurationException);

                                throw;
                            }
                        }
                    }
                }
                return writer;
            }
        }

        internal static void TryLogConfigurationFailure(ActivationException configurationException)
        {
            try
            {
                var logger = EnterpriseLibraryContainer.Current.GetInstance<DefaultLoggingEventLogger>();
                logger.LogConfigurationError(configurationException);
            }
            catch
            { }
        }
    }
}
